﻿
Public Class usclient
    Public Const defaultConfigfile As String = "usclient.ini"
    Private WithEvents config As configMonitor = Nothing
    Private WithEvents xmlapi As usapilib.asyncapi = Nothing

    Private Class mouseAction
        Public Shared downX As Int64
        Public Shared downY As Int64
    End Class

    Private Class keyboardAction
        Public Shared shift As Boolean
        Public Shared ctrl As Boolean
        Public Shared alt As Boolean
    End Class

    Private Class configuration
        Public Shared address As String
        Public Shared usexmlapi As Boolean
        Public Shared homepage As String
        Public Shared opacity As Double
        Public Shared topmost As Boolean
        Public Shared movewithshift As Boolean
        Public Shared movewithctrl As Boolean
        Public Shared movewithalt As Boolean
        Public Shared width As Int64
        Public Shared height As Int64
        Public Shared left As Int64
        Public Shared right As Int64
        Public Shared top As Int64
        Public Shared bottom As Int64
    End Class

    Private Sub loadconfig()
        assert(Not config Is Nothing, "config should not be nothing when loadconfig.")
        config.trygetparameter(configNaming.usclient.name, configNaming.usclient.address, configuration.address _
                               , configNaming.defaultValue.usclient.address)
        config.trygetparameter(configNaming.usclient.name, configNaming.usclient.usexmlapi, configuration.usexmlapi _
                                , configNaming.defaultValue.usclient.usexmlapi)
        config.trygetparameter(configNaming.usclient.name, configNaming.usclient.homepage, configuration.homepage _
                                , configNaming.defaultValue.usclient.homepage)
        config.trygetparameter(configNaming.usclient.name, configNaming.usclient.opacity, configuration.opacity _
                                , configNaming.defaultValue.usclient.opacity)
        config.trygetparameter(configNaming.usclient.name, configNaming.usclient.topmost, configuration.topmost _
                                , configNaming.defaultValue.usclient.topmost)
        config.trygetparameter(configNaming.usclient.name, configNaming.usclient.movewithshift _
                               , configuration.movewithshift, configNaming.defaultValue.usclient.movewithshift)
        config.trygetparameter(configNaming.usclient.name, configNaming.usclient.movewithctrl _
                                , configuration.movewithctrl, configNaming.defaultValue.usclient.movewithctrl)
        config.trygetparameter(configNaming.usclient.name, configNaming.usclient.movewithalt _
                                , configuration.movewithalt, configNaming.defaultValue.usclient.movewithalt)
        config.trygetparameter(configNaming.usclient.name, configNaming.usclient.width, configuration.width _
                                , configNaming.defaultValue.usclient.width)
        config.trygetparameter(configNaming.usclient.name, configNaming.usclient.height, configuration.height _
                                , configNaming.defaultValue.usclient.height)
        config.trygetparameter(configNaming.usclient.name, configNaming.usclient.left, configuration.left _
                                , configNaming.defaultValue.usclient.left)
        config.trygetparameter(configNaming.usclient.name, configNaming.usclient.right, configuration.right _
                                , configNaming.defaultValue.usclient.right)
        config.trygetparameter(configNaming.usclient.name, configNaming.usclient.top, configuration.top _
                                , configNaming.defaultValue.usclient.top)
        config.trygetparameter(configNaming.usclient.name, configNaming.usclient.bottom, configuration.bottom _
                                , configNaming.defaultValue.usclient.bottom)

        On Error Resume Next
        Opacity = configuration.opacity
        TopMost = configuration.topmost
        If configuration.width > 0 Then
            Width = configuration.width
        End If
        If configuration.height > 0 Then
            Height = configuration.height
        End If
        If configuration.right > 0 Then
            Left = Screen.PrimaryScreen.WorkingArea.Width - configuration.right
        ElseIf configuration.left > 0 Then
            Left = configuration.left
        End If
        If configuration.top > 0 Then
            Top = configuration.top
        ElseIf configuration.bottom > 0 Then
            Top = Screen.PrimaryScreen.WorkingArea.Height - configuration.bottom
        End If
        workingShow.Visible = configuration.usexmlapi
        If configuration.usexmlapi Then
            xmlapi = New usapilib.asyncapi(configuration.address, 1)
            workingShow.Image = images.Images("radiobutton1.off.PNG")
        Else
            xmlapi = Nothing
        End If
    End Sub

    Private Sub usclient_DragDrop(ByVal sender As Object _
                                  , ByVal e As System.Windows.Forms.DragEventArgs) Handles Me.DragDrop
        On Error Resume Next
        Dim url As String = Nothing
        If e.Data.GetDataPresent(DataFormats.UnicodeText, True) Then
            url = e.Data.GetData(DataFormats.UnicodeText, True)
        ElseIf e.Data.GetDataPresent(DataFormats.Text, True) Then
            url = e.Data.GetData(DataFormats.Text, True)
        Else
            Dim sr As IO.StreamReader = Nothing
            Dim formats() As String = Nothing
            formats = e.Data.GetFormats(True)
            sr = New IO.StreamReader(convertor.cast(Of IO.Stream)(e.Data.GetData(formats(formats.Length() - 1)), False))
            url = sr.ReadToEnd()
        End If
        handleUrl(url)
    End Sub

    Private Sub usclient_DragEnter(ByVal sender As Object _
                                   , ByVal e As System.Windows.Forms.DragEventArgs) Handles Me.DragEnter
        If e.AllowedEffect() And DragDropEffects.Copy Then
            e.Effect() = DragDropEffects.Copy
        ElseIf e.AllowedEffect() And DragDropEffects.Link Then
            e.Effect() = DragDropEffects.Link
        ElseIf e.AllowedEffect() And DragDropEffects.Move Then
            e.Effect() = DragDropEffects.Move
        Else
            e.Effect() = DragDropEffects.None
        End If
    End Sub

    Private Sub usclient_QueryContinueDrag(ByVal sender As Object _
                                           , ByVal e As System.Windows.Forms.QueryContinueDragEventArgs) _
                                           Handles Me.QueryContinueDrag
        If e.EscapePressed Then
            e.Action = DragAction.Cancel
        End If
    End Sub

    Private Sub usclient_FormClosing(ByVal sender As Object _
                                     , ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        notifyIcon.Visible = False
        If Not xmlapi Is Nothing Then
            xmlapi.close()
        End If
    End Sub

    Private Sub usclient_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        If isreleasebuild() Then
            errorHandle.initial(errorHandle.displayMode.msgbox)
        Else
            errorHandle.initial(errorHandle.defaultLogFilename)
        End If

        notifyIcon.Text = applicationSign()
        notifyIcon.Visible = True
        tooltip.ToolTipIcon = ToolTipIcon.Info
        tooltip.ToolTipTitle = applicationSign()
        tooltip.SetToolTip(Me, applicationDescription())
        tooltip.AutoPopDelay = maxInt32

        Dim configfile As String = Nothing
        If My.Application.CommandLineArgs.Count() > 0 Then
            configfile = My.Application.CommandLineArgs(0)
        Else
            configfile = defaultConfigfile
        End If
        config = New configMonitor()
        If Not config.open(configfile) Then
            raiseError("cannot open configuration file " + configfile + ", use default values." _
                       , errorHandle.errorType.warning)
        End If
        loadconfig()
    End Sub

    Private Sub config_ConfigChanged() Handles config.ConfigChanged
        loadconfig()
    End Sub

    Private Sub usclient_MouseDown(ByVal sender As Object _
                                 , ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
        mouseAction.downX = e.X
        mouseAction.downY = e.Y
    End Sub

    Private Sub usclient_MouseMove(ByVal sender As Object _
                                 , ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
        If e.Button = Windows.Forms.MouseButtons.Left _
            AndAlso (keyboardAction.shift OrElse Not configuration.movewithshift) _
            AndAlso (keyboardAction.ctrl OrElse Not configuration.movewithctrl) _
            AndAlso (keyboardAction.alt OrElse Not configuration.movewithalt) Then
            On Error Resume Next
            Me.Left += e.X - mouseAction.downX
            Me.Top += e.Y - mouseAction.downY
        End If
    End Sub

    Private Sub handleUrl(ByVal url As String)
        If Not isemptystring(url) AndAlso Not isemptystring(configuration.address) Then
            If configuration.usexmlapi Then
                workingShow.Image = images.Images("radiobutton1.on.PNG")
                xmlapi.submit(Nothing, url)
            Else
                Dim target As String = Nothing
                copy(target, configuration.address)
                strrplc(target, "{url}", urlUtils.urlencode(url, encoding.utf8))
                On Error Resume Next
                Process.Start("explorer", """" + target + """")
            End If
        End If
    End Sub

    Private Sub exitMenuItem_Click(ByVal sender As System.Object _
                                   , ByVal e As System.EventArgs) Handles exitMenuItem.Click
        Application.Exit()
    End Sub

    Private Sub fromClipboardMenuItem_Click(ByVal sender As Object _
                                            , ByVal e As System.EventArgs) Handles fromClipboardMenuItem.Click
        handleUrl(Clipboard.GetText())
    End Sub

    Private Sub notifyIcon_MouseClick(ByVal sender As Object _
                                      , ByVal e As System.Windows.Forms.MouseEventArgs) Handles notifyIcon.MouseClick
        Me.Show()
        Me.TopLevel = True
    End Sub

    Private Sub usclient_MouseDoubleClick(ByVal sender As Object _
                                          , ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDoubleClick
        If Not isemptystring(configuration.homepage) Then
            On Error Resume Next
            Process.Start(configuration.homepage)
        End If
    End Sub

    Private Sub notifyIcon_MouseDoubleClick(ByVal sender As Object _
                                            , ByVal e As System.Windows.Forms.MouseEventArgs) _
                                            Handles notifyIcon.MouseDoubleClick
        usclient_MouseDoubleClick(Nothing, Nothing)
    End Sub

    Private Sub usclient_KeyDown(ByVal sender As Object _
                                 , ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
        keyboardAction.shift = e.Shift
        keyboardAction.ctrl = e.Control
        keyboardAction.alt = e.Alt
    End Sub

    Private Sub usclient_KeyUp(ByVal sender As Object _
                               , ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyUp
        usclient_KeyDown(sender, e)
    End Sub

    Private Delegate Sub setClipboardDelegate(ByVal text As String)

    Private Sub setClipboard(ByVal text As String)
        Clipboard.Clear()
        Clipboard.SetText(text)
    End Sub

    Private Sub xmlapi_finishaction(ByVal info As usapilib.asyncapi.info) Handles xmlapi.finishaction
        workingShow.Image = images.Images("radiobutton1.off.PNG")
        If info.actionResult AndAlso info.submitResult = usshare.submitResult.success _
            AndAlso Not isemptystring(info.shortUrl) Then
            Invoke(New setClipboardDelegate(AddressOf setClipboard), info.shortUrl)
        Else
            raiseError("cannot submit url " + info.url() + ", error " + usshare.display(info.submitResult) _
                       , errorHandle.errorType.warning)
        End If
    End Sub

    Private Sub editConfigMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles editConfigMenuItem.Click
        On Error Resume Next
        Process.Start("""" + config.configfile() + """")
    End Sub
End Class
